/**************************************************************************************************
* Filename:			InputManager.h
* Date:				03/05/10
* Mod. Date:		05/16/10
* Mod. Initials:	MG
* Author:			Malcolm J. Gruber
* Purpose:			A system used to manage input, and allow multiple inputs for the same
*					container.
**************************************************************************************************/

#include "InputManager.h"

/*************************************************************************
* InputManager::InputContainer - Input Container
*************************************************************************/

/*************************************************************************
* InputContainer():			Constructor for InputContainer
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
InputManager::InputContainer::InputContainer(void)
{
	// Clears all buffers
	m_lKeyboard.RemoveAll();
	m_lMouse.RemoveAll();
	m_uInputString[0] = 0;
}

/*************************************************************************
* ~InputContainer():			Destructor for InputContainer
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
InputManager::InputContainer::~InputContainer(void)
{
	// Clears all buffers
	m_lKeyboard.RemoveAll();
	m_lMouse.RemoveAll();
	m_uInputString[0] = 0;
}

/*************************************************************************
* InputDown():					Checks to see if the desired input is
*								being held down.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::InputContainer::InputDown(void)
{
	// Get the instance to direct input
	DirectInput* di = DirectInput::GetInstance();

	// Loop through the keyboard inputs
	for(unsigned int k = 0; k < m_lKeyboard.Size(); k++)
	{
		if(di->KeyDown(m_lKeyboard[k]))
			return true;
	}

	// Loop through the mouse inputs
	for(unsigned int m = 0; m < m_lMouse.Size(); m++)
	{
		if(di->MouseButtonDown(m_lMouse[m]))
			return true;
	}

	return false;
}

/*************************************************************************
* InputPressed():				Checks to see if the desired input is
*								pressed.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::InputContainer::InputPressed(void)
{
	// Get the instance to direct input
	DirectInput* di = DirectInput::GetInstance();

	// Loop through the keyboard inputs
	for(unsigned int k = 0; k < m_lKeyboard.Size(); k++)
	{
		if(di->KeyPressed(m_lKeyboard[k]))
			return true;
	}

	// Loop through the mouse inputs
	for(unsigned int m = 0; m < m_lMouse.Size(); m++)
	{
		if(di->MouseButtonPressed(m_lMouse[m]))
			return true;
	}

	return false;
}

/*************************************************************************
* InputPressedEx():				Checks to see if the desired buffered 
*								input is pressed.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::InputContainer::InputPressedEx(void)
{
	// Get the instance to direct input
	DirectInput* di = DirectInput::GetInstance();

	// Loop through the keyboard inputs
	for(unsigned int k = 0; k < m_lKeyboard.Size(); k++)
	{
		if(di->KeyPressedEx(m_lKeyboard[k]))
			return true;
	}

	// Loop through the mouse inputs
	for(unsigned int m = 0; m < m_lMouse.Size(); m++)
	{
		if(di->MouseButtonPressedEx(m_lMouse[m]))
			return true;
	}

	return false;
}

/*************************************************************************
* InputUp():					Checks to see if the desired input is up.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::InputContainer::InputUp(void)
{
	// Get the instance to direct input
	DirectInput* di = DirectInput::GetInstance();

	// Loop through the keyboard inputs
	for(unsigned int k = 0; k < m_lKeyboard.Size(); k++)
	{
		if(di->KeyUp(m_lKeyboard[k]))
			return true;
	}

	// Loop through the mouse inputs
	for(unsigned int m = 0; m < m_lMouse.Size(); m++)
	{
		if(di->MouseButtonUp(m_lMouse[m]))
			return true;
	}

	return false;
}

/*************************************************************************
* InputReleased():				Checks to see if the desired input is
*								released.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::InputContainer::InputReleased(void)
{
	// Get the instance to direct input
	DirectInput* di = DirectInput::GetInstance();

	// Loop through the keyboard inputs
	for(unsigned int k = 0; k < m_lKeyboard.Size(); k++)
	{
		if(di->KeyReleased(m_lKeyboard[k]))
			return true;
	}

	// Loop through the mouse inputs
	for(unsigned int m = 0; m < m_lMouse.Size(); m++)
	{
		if(di->MouseButtonReleased(m_lMouse[m]))
			return true;
	}

	return false;
}

/*************************************************************************
* InputReleasedEx():			Checks to see if the desired buffered 
*								input is released.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::InputContainer::InputReleasedEx(void)
{
	// Get the instance to direct input
	DirectInput* di = DirectInput::GetInstance();

	// Loop through the keyboard inputs
	for(unsigned int k = 0; k < m_lKeyboard.Size(); k++)
	{
		if(di->KeyReleasedEx(m_lKeyboard[k]))
			return true;
	}

	// Loop through the mouse inputs
	for(unsigned int m = 0; m < m_lMouse.Size(); m++)
	{
		if(di->MouseButtonReleasedEx(m_lMouse[m]))
			return true;
	}

	return false;
}

/*************************************************************************
* AddMouse():					Adds a mouse input value to the
*								mouse input value list.
*
* Ins:							unsigned char uInput
*
* Outs:							void
*
* Returns:						void
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
void InputManager::InputContainer::AddMouse(unsigned char uInput)
{
	m_lMouse.AddBack(uInput);
}

/*************************************************************************
* AddKeyboard():				Adds a keyboard input value to the 
*								keyboard input value list.
*
* Ins:							unsigned char uInput
*
* Outs:							void
*
* Returns:						void
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
void InputManager::InputContainer::AddKeyboard(unsigned char uInput)
{
	m_lKeyboard.AddBack(uInput);
}

/*************************************************************************
* GetInputString():				Retrieves the string of the input 
*								container.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						const char*
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
const char* InputManager::InputContainer::GetInputString(void)
{
	return m_uInputString;
}

/*************************************************************************
* SetString():					Sets the string of the input container.
*
* Ins:							const char*
*
* Outs:							void
*
* Returns:						void
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
void InputManager::InputContainer::SetString(const char* cString)
{
	strcpy_s((char*)m_uInputString, 32, (char*)cString);
}

/*************************************************************************
* InputManager - Input Manager
*************************************************************************/
InputManager InputManager::m_Instance;

/*************************************************************************
* GetInstance():				Returns the instance of the input 
*								manager.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						const char*
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
InputManager* InputManager::GetInstance(void)
{
	return &m_Instance;
}

/*************************************************************************
* InputManager():				Constructor for InputManager
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
InputManager::InputManager(void)
{
	m_DI = NULL;
	ClearInput();
}

/*************************************************************************
* ~InputManager():				Destructor for InputManager
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
InputManager::~InputManager(void)
{
	Shutdown();
}

/*************************************************************************
* InitInputManager():			Initiate the input manager, taking in a 
*								handle and instance to the window.
*								Device flags:
*									DIK_KEYBOARD
*									DIK_MOUSE
*
* Ins:							HWND hWnd
*								HINSTANCE hInstance
*								int32_t unDevices
*								int32_t unExclusive
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::Initialize(HWND hWnd, HINSTANCE hInstance, int32_t unDevices, int32_t unExclusive)
{
	// Get the Direct Input instance
	m_DI = DirectInput::GetInstance();
	
	// Initalizes Direct Input
	if( !m_DI->InitDirectInput(hWnd, hInstance, unDevices, unExclusive) )
		return false;

	// Hold onto the window handle for cursor
	m_hWnd = hWnd;

	// Clear all the input
	ClearInput();

	SetMouseX(0);
	SetMouseY(0);
	
	m_Max.x = 0;
	m_Max.y = 0;
	m_Min.x = 0;
	m_Min.y = 0;

	return true;
}

/*************************************************************************
* ShutdownInputManager():		Shuts down the input manager
*
* Ins:							void
*
* Outs:							void
*
* Returns:						void
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
void InputManager::Shutdown(void)
{
	// Clear all the input
	ClearInput();
	
	// If Direct Input has been initalized, shutdown
	if( m_DI )
		m_DI->ShutdownDirectInput();
	
	m_DI = NULL;
}

/*************************************************************************
* UpdateDevices():				Updates the image of all input devices.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						void
*
* Mod. Date:					05/16/10
* Mod. Initials:				MG
*************************************************************************/
void InputManager::UpdateDevices(void)
{
	if( m_DI )
	{
		m_DI->ReadDevices();
		POINT cursorPos;
		GetCursorPos(&cursorPos);
		ScreenToClient(m_hWnd, &cursorPos);
		m_WinMouseX = cursorPos.x;
		m_WinMouseY = cursorPos.y;
		m_MouseX = m_DI->GetMousePosX();
		m_MouseY = m_DI->GetMousePosY();
		BindMouse();
	}
}

/*************************************************************************
* InputDown():					Checks to see if the desired input is
*								being held down.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::InputDown(const char* Input)
{
	// Make sure the string isn't null
	if( !Input )
		return false;

	// Copy the string and lowercase it
	char string[32];
	strncpy_s(string, 32, Input, 31);

	strncpy_s(string, 32, ToLowerCase(string), 31);
	string[31] = 0;

	// Look through all inputs
	for(unsigned int i = 0; i < m_lInput.Size(); i++)
	{
		if( 0 == strcmp(m_lInput[i].GetInputString(), string) )
		{
			return m_lInput[i].InputDown();
		}
	}

	return false;
}

/*************************************************************************
* InputPressed():					Checks to see if the desired input is
*								being pressed.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::InputPressed(const char* Input)
{
	// Make sure the string isn't null
	if( !Input )
		return false;

	// Copy the string and lowercase it
	char string[32];
	strncpy_s(string, 32, Input, 31);

	strncpy_s(string, 32, ToLowerCase(string), 31);
	string[31] = 0;

	// Look through all inputs
	for(unsigned int i = 0; i < m_lInput.Size(); i++)
	{
		if( 0 == strcmp(m_lInput[i].GetInputString(), string) )
		{
			return m_lInput[i].InputPressed();
		}
	}

	return false;
}

/*************************************************************************
* InputPressedEx():				Checks to see if the desired buffered
*								input is being held down.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::InputPressedEx(const char* Input)
{
	// Make sure the string isn't null
	if( !Input )
		return false;

	// Copy the string and lowercase it
	char string[32];
	strncpy_s(string, 32, Input, 31);

	strncpy_s(string, 32, ToLowerCase(string), 31);
	string[31] = 0;

	// Look through all inputs
	for(unsigned int i = 0; i < m_lInput.Size(); i++)
	{
		if( 0 == strcmp(m_lInput[i].GetInputString(), string) )
		{
			return m_lInput[i].InputPressedEx();
		}
	}

	return false;
}

/*************************************************************************
* InputUp():					Checks to see if the desired input is
*								not pressed.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::InputUp(const char* Input)
{
	// Make sure the string isn't null
	if( !Input )
		return false;

	// Copy the string and lowercase it
	char string[32];
	strncpy_s(string, 32, Input, 31);

	strncpy_s(string, 32, ToLowerCase(string), 31);
	string[31] = 0;

	// Look through all inputs
	for(unsigned int i = 0; i < m_lInput.Size(); i++)
	{
		if( 0 == strcmp(m_lInput[i].GetInputString(), string) )
		{
			return m_lInput[i].InputUp();
		}
	}

	return false;
}

/*************************************************************************
* InputReleased():				Checks to see if the desired input is 
*								released.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::InputReleased(const char* Input)
{
	// Make sure the string isn't null
	if( !Input )
		return false;

	// Copy the string and lowercase it
	char string[32];
	strncpy_s(string, 32, Input, 31);

	strncpy_s(string, 32, ToLowerCase(string), 31);
	string[31] = 0;

	// Look through all inputs
	for(unsigned int i = 0; i < m_lInput.Size(); i++)
	{
		if( 0 == strcmp(m_lInput[i].GetInputString(), string) )
		{
			return m_lInput[i].InputReleased();
		}
	}

	return false;
}

/*************************************************************************
* InputReleasedEx():			Checks to see if the desired buffered 
*								input is released.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::InputReleasedEx(const char* Input)
{
	// Make sure the string isn't null
	if( !Input )
		return false;

	// Copy the string and lowercase it
	char string[32];
	strncpy_s(string, 32, Input, 31);

	strncpy_s(string, 32, ToLowerCase(string), 31);
	string[31] = 0;

	// Look through all inputs
	for(unsigned int i = 0; i < m_lInput.Size(); i++)
	{
		if( 0 == strcmp(m_lInput[i].GetInputString(), string) )
		{
			return m_lInput[i].InputReleasedEx();
		}
	}

	return false;
}
/*************************************************************************
* GetWinMouseX():				Returns the X position of the mouse. (Win)
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
int InputManager::GetWinMouseX(void)
{
	return m_WinMouseX;
}
/*************************************************************************
* GetWinMouseY():				Returns the Y position of the mouse. (Win)
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
int InputManager::GetWinMouseY(void)
{
	return m_WinMouseY;
}
/*************************************************************************
* GetMouseX():					Returns the X position of the mouse.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
int InputManager::GetMouseX(void)
{
	m_MouseX = m_DI->GetMousePosX();
	BindMouse();
	return m_MouseX;
}

/*************************************************************************
* GetMouseY():					Returns the Y position of the mouse.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
int InputManager::GetMouseY(void)
{
	m_MouseY = m_DI->GetMousePosY();
	BindMouse();
	return m_MouseY;
}
/*************************************************************************
* SetMouseX():					Sets the X position of the mouse.
*
* Ins:							int mouseX
*
* Outs:							void
*
* Returns:						void
*
* Mod. Date:					05/16/10
* Mod. Initials:				MG
*************************************************************************/
void InputManager::SetMouseX(int mouseX)
{
	m_DI->SetMousePosX(mouseX);
}
/*************************************************************************
* SetMouseY():					Sets the Y position of the mouse.
*
* Ins:							int mouseY
*
* Outs:							void
*
* Returns:						void
*
* Mod. Date:					05/16/10
* Mod. Initials:				MG
*************************************************************************/
void InputManager::SetMouseY(int mouseY)
{
	m_DI->SetMousePosY(mouseY);
}
/*************************************************************************
* GetMouseSpeedX():				Returns the speed of the mouse along the
*								X axis.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
int InputManager::GetMouseSpeedX(void)
{
	return m_DI->MouseSpeedX();
}

/*************************************************************************
* GetMouseSpeedY():				Returns the speed of the mouse along the
*								Y axis.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
int InputManager::GetMouseSpeedY(void)
{
	return m_DI->MouseSpeedY();
}

/*************************************************************************
* GetMouseScrollSpeed():		Returns the speed of the mouses
*								scrollwheel.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
int InputManager::GetMouseScrollSpeed(void)
{
	return m_DI->MouseSpeedWheel();
}

/*************************************************************************
* AddMouse():					Adds a mouse input value to the
*								mouse input value list with the correct
*								string if it already exist, if not,
*								creates a new string.
*
* Ins:							const char* cString
*								unsigned char uInput
*
* Outs:							void
*
* Returns:						void
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
void InputManager::AddMouse(const char* cString, unsigned char uInput)
{
	// Make sure the string isn't null
	if( !cString )
		return;

	// Copy the string and lowercase it
	char string[32];
	strncpy_s(string, 32, cString, 31);

	strncpy_s(string, 32, ToLowerCase(string), 31);
	string[31] = 0;

	// Look through all inputs to see if it exist
	for(unsigned int i = 0; i < m_lInput.Size(); i++)
	{
		if( 0 == strcmp(m_lInput[i].GetInputString(), string) )
		{
			m_lInput[i].AddMouse(uInput);
		}
	}

	// Create a new input container if there isn't one existing
	InputContainer newInput;
	newInput.SetString(string);
	newInput.AddMouse(uInput);
	m_lInput.AddBack(newInput);
}

/*************************************************************************
* AddKeyboard():				Adds a keyboard input value to the
*								keyboard input value list with the correct
*								string if it already exist, if not,
*								creates a new string.
*
* Ins:							const char* cString
*								unsigned char uInput
*
* Outs:							void
*
* Returns:						void
*
* Mod. Date:					04/05/10
* Mod. Initials:				MG
*************************************************************************/
void InputManager::AddKeyboard(const char* cString, unsigned char uInput)
{
	// Make sure the string isn't null
	if( !cString )
		return;

	// Copy the string and lowercase it
	char string[32];
	strncpy_s(string, 32, cString, 31);

	strncpy_s(string, 32, ToLowerCase(string), 31);
	string[31] = 0;

	// Look through all inputs to see if it exist
	for(unsigned int i = 0; i < m_lInput.Size(); i++)
	{
		if( 0 == strcmp(m_lInput[i].GetInputString(), string) )
		{
			m_lInput[i].AddKeyboard(uInput);
		}
	}

	// Create a new input container if there isn't one existing
	InputContainer newInput;
	newInput.SetString(string);
	newInput.AddKeyboard(uInput);
	m_lInput.AddBack(newInput);
}

/*************************************************************************
* ToLowerCase():				Takes in a string and makes it entirely
*								lowercase.
*
* Ins:							char* cString
*
* Outs:							void
*
* Returns:						char*
*
* Mod. Date:					03/10/10
* Mod. Initials:				MG
*************************************************************************/
char* InputManager::ToLowerCase(char* cString)
{
	// Get the length of the string
	int len = strlen(cString);

	// Get another pointer to it for iteration
	char* str = cString;
	for(int l = 0; l < len; l++)
	{
		if( (*str) <= 'Z' && (*str) >= 'A' )
			(*str) = (*str)-('Z' - 'z');

		str++;
	}

	return cString;
}

/*************************************************************************
* MouseInside():				Check to see if the mouse is inside the
*								rectangle.
*
* Ins:							Rect& section
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					05/16/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::MouseInside(const RECT &section)
{
	POINT mouse;
	mouse.x = m_MouseX;
	mouse.y = m_MouseY;
	return (PtInRect(&section, mouse) ? true : false);
}
/*************************************************************************
* MouseInside():				Check to see if the mouse is inside the
*								circle.
*
* Ins:							POINT &center
*								float radius
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					05/16/10
* Mod. Initials:				MG
*************************************************************************/
bool InputManager::MouseInside(const POINT &center, float radius)
{
	float dX = (float)(center.x - m_MouseX);
	float dY = (float)(center.y - m_MouseY);
	float distance = (dX*dX) + (dY*dY);

	return (radius*radius) > distance;
}
/*************************************************************************
* SetMouseBounds():				Sets the max for mouse to move.
*
* Ins:							long minX
*								long minY
*								long maxX
*								long maxY
*
* Outs:							void
*
* Returns:						bool
*
* Mod. Date:					05/16/10
* Mod. Initials:				MG
*************************************************************************/
void InputManager::SetMouseBounds(long minX, long minY, long maxX, long maxY)
{
	m_Max.x = maxX;
	m_Max.y = maxY;
	m_Min.x = minX;
	m_Min.y = minY;
}

/*************************************************************************
* BindMouse():					Bounds the mouse inside the min and max.
*
* Ins:							void
*
* Outs:							void
*
* Returns:						void
*
* Mod. Date:					05/16/10
* Mod. Initials:				MG
*************************************************************************/
void InputManager::BindMouse(void)
{
	if( m_MouseX < m_Min.x )
		m_MouseX = m_Min.x;
	if( m_MouseY < m_Min.y )
		m_MouseY = m_Min.y;

	if( m_MouseX > m_Max.x )
		m_MouseX = m_Max.x;
	if( m_MouseY > m_Max.y )
		m_MouseY = m_Max.y;

	m_DI->SetMousePosX(m_MouseX);
	m_DI->SetMousePosY(m_MouseY);
}

void InputManager::SetMouseSensitivity( int nSensValue )
{
	m_DI->SetMouseSensitivity(nSensValue);
}

int InputManager::GetMouseSensitivity( void )
{
	return m_DI->GetMouseSensitivity();
}

